home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 21 / CU Amiga Magazine's Super CD-ROM 21 (1998)(EMAP Images)(GB)[!][issue 1998-04].iso / CUCD / Programming / Python-1.4 / Source / Amiga / Python_netlib / popen.c < prev    next >
C/C++ Source or Header  |  1994-11-17  |  9KB  |  349 lines

  1. RCS_ID_C="$Id: popen.c,v 4.2 1994/11/17 22:20:30 jraja Exp $";
  2. /*
  3.  *      popen.c - Unix comaptible popen() and pclose()
  4.  *
  5.  *      Author: Rick Schaeffer <ricks@isc-br.isc-br.com>
  6.  */
  7.  
  8. /****** net.lib/popen *******************************************************
  9.     NAME
  10.         popen, pclose - initiate I/O to/from a process
  11.  
  12.     SYNOPSIS
  13.         #include <stdio.h>
  14.  
  15.         FILE *popen(command, type)
  16.         char *command, *type;
  17.  
  18.         pclose(stream)
  19.         FILE *stream;
  20.  
  21.     DESCRIPTION
  22.         The arguments to popen are pointers to null-terminated
  23.         strings containing respectively a command line and an
  24.         I/O mode, either "r" for reading or "w" for writing.  It
  25.         creates a pipe between the calling process and the command
  26.         to be executed.  The value returned is a stream pointer that
  27.         can be used (as appropriate) to write to the standard input
  28.         of the command or read from its standard output.
  29.  
  30.         A stream opened by popen **MUST** be closed by pclose, which
  31.         waits for the associated process to terminate and returns
  32.         the exit status of the command.
  33.  
  34.         Because stdio files are shared, a type "r" command may be
  35.         used as an input filter, and a type "w" as an output filter.
  36.  
  37.     DIAGNOSTICS
  38.         Popen returns a null pointer if files or processes cannot be
  39.         created.
  40.  
  41.         Pclose returns -1 if stream is not associated with a
  42.         `popened' command.
  43.  
  44.     AUTHOR
  45.         Original version by Rick Schaeffer <ricks@isc-br.isc-br.com>
  46. */
  47.  
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <stdarg.h>
  52.  
  53. #include <exec/types.h>
  54. #include <exec/memory.h>
  55. #include <dos/dos.h>
  56. #include <dos/dosextens.h>
  57. #include <dos/record.h>
  58. #include <dos/dostags.h>
  59.  
  60. #include <proto/exec.h>
  61. #include <proto/dos.h>
  62. #include <clib/alib_protos.h>
  63.  
  64. #include <errno.h>
  65.  
  66. #define NOTDEF
  67.  
  68. extern char *mktemp(char *);
  69.  
  70. struct POmsg {
  71.     struct Message  POm;
  72.     int     rc;
  73.     char        *cmd;
  74.     struct Library  *DOSBase;
  75.     };
  76.  
  77.  
  78. struct pstruct {
  79.     FILE    *fptr;
  80.     struct POmsg    childmsg;
  81.     };
  82.  
  83. #define MAXPIPES    6
  84. static struct pstruct poarray[MAXPIPES] = { 0 };
  85.  
  86. static int childprocess(void);
  87.  
  88. FILE *popen(const char *cmd, const char *mode)
  89. {
  90.     static char tempname[] = "pipe:pXXX.XXX";
  91.     char        *pname,redir[20];
  92.     short       i;
  93.     int         pmode;
  94.     struct pstruct  *poptr;
  95.     struct Process  *child;
  96.     struct CommandLineInterface *cli;
  97.     ULONG stacksize;
  98.     struct Process *thistask;
  99.     FILE            *fptr;
  100.  
  101.     /* First, get pointers to our process and cli structs */
  102.     thistask = (struct Process *) FindTask(NULL);
  103.     cli = Cli();
  104.     poptr = NULL;
  105.  
  106.     /* now find an open pipe (we currently only allow 6 simultaneously
  107.        open pipes) */
  108.     for (i=0; i<MAXPIPES; i++) {
  109.         if (poarray[i].fptr == NULL) {
  110.             poptr = &poarray[i];
  111.             break;
  112.             }
  113.         }
  114.     if (poptr == NULL) {
  115.         fprintf(stderr,"popen: Unable to find an open pipe\n");
  116.         errno = EMFILE;
  117.         return(NULL);
  118.         }
  119.     if (strcmp(mode,"r") == 0)
  120.         pmode = MODE_NEWFILE;
  121.     else if (strcmp(mode,"w") == 0)
  122.         pmode = MODE_OLDFILE;
  123.     else {
  124.         fprintf(stderr,"popen: Mode must be 'r' or 'w'\n");
  125.         errno = EINVAL;
  126.         return(NULL);
  127.         }
  128.  
  129.     /* Try to make a guaranteed unique file name for the pipe */
  130.     strcpy(redir,tempname);
  131.     redir[5] = 'a' + i;
  132.  
  133.     pname = mktemp(redir);            /* set up a pipe: file name */
  134.  
  135.     /* Now get the child's stack and priority set up */
  136.     if (cli)
  137.         stacksize = cli->cli_DefaultStack << 2;
  138.     else
  139.         stacksize = thistask->pr_StackSize;
  140.  
  141.     /* Now open our side of the pipe */
  142.     fptr = fopen(pname,mode);
  143.     if (fptr == NULL) {
  144.         fprintf(stderr,"popen: Unable to open pipe file %s\n",pname);
  145.         return(NULL);
  146.         }
  147.  
  148.     /* create the command.  since the "System" function runs through
  149.        the default shell, we need to tell it not to fail so that we
  150.        ALWAYS get back the exit status.  This wouldn't be necessary
  151.        if the CLI created by the System function inherited the parent's
  152.        FAILAT level.
  153.        The pipe file is passed as redirection to shell, which the 
  154.        SystemTags() will parse. For some reason the default "more"
  155.        could not get it's input properly if redirection was not used.
  156.     */
  157.     poptr->childmsg.cmd = malloc(strlen(cmd) + 15 + 20);
  158.     sprintf(poptr->childmsg.cmd, "failat 9999\n%s %c%s\n",
  159.         cmd, (pmode == MODE_NEWFILE) ? '>' : '<', pname);
  160.  
  161.     /* Create a port that we can get the child's exit status through */
  162.     poptr->childmsg.POm.mn_ReplyPort = CreateMsgPort();
  163.     poptr->childmsg.POm.mn_Node.ln_Type = NT_MESSAGE;
  164.     poptr->childmsg.POm.mn_Node.ln_Pri = 0;
  165.     if (poptr->childmsg.POm.mn_ReplyPort == 0) {
  166.         fclose(fptr);
  167.         fprintf(stderr,"popen: Couldn't create message port\n");
  168.         errno = ENOMEM;
  169.         return(NULL);
  170.         }
  171.  
  172.     /* Now we can start the new process.  NOTE: this is actually going
  173.        to create a process consisting ONLY of the function "childprocess"
  174.        which can be seen below.  childprocess() then runs the command
  175.        passed in the startup message.
  176.     */
  177.     child = CreateNewProcTags(
  178.         NP_Entry,   (Tag) childprocess,
  179.         NP_Input,   Input(),
  180.         NP_Output,  Output(),
  181.         NP_CloseInput,  FALSE,
  182.         NP_CloseOutput, FALSE,
  183.         NP_StackSize,   stacksize,
  184.         NP_Cli,     TRUE,
  185.         TAG_DONE
  186.         );
  187.  
  188.     poptr->childmsg.DOSBase = (struct Library *)DOSBase;
  189.  
  190.     /* now pass the child the startup message */
  191.     PutMsg(&child->pr_MsgPort,(struct Message *) &poptr->childmsg);
  192.  
  193.     return(poptr->fptr = fptr);
  194. }
  195.  
  196. FILE *popenl(const char *arg0, ...)
  197. {
  198.     va_list ap;
  199.     char argbuf[512], *mode;
  200.  
  201.     strcpy(argbuf, arg0);
  202.     va_start(ap, arg0);
  203.     while(1)
  204.     {
  205.         char *s = va_arg(ap, char *);
  206.  
  207.         if(s == NULL)
  208.         {
  209.         strcat(argbuf, "\n");
  210.         break;
  211.         } /* if */
  212.  
  213.         strcat(argbuf, " ");
  214.  
  215.         if(strchr(s, ' '))
  216.         {
  217.         strcat(argbuf, "\"");
  218.         strcat(argbuf, s);
  219.         strcat(argbuf, "\"");
  220.         }
  221.         else
  222.         {
  223.         strcat(argbuf, s);
  224.         } /* if */
  225.     }
  226.     mode = va_arg(ap, char *);
  227.     va_end(ap);
  228.  
  229.     return(popen(argbuf, mode));
  230.  
  231. } /* popenl */
  232.  
  233. int pclose(FILE *fptr)
  234. {
  235.     short       i;
  236.  
  237.     /* Figure out which pipe we used for this file */
  238.     for (i=0; i<MAXPIPES; i++)
  239.         if (poarray[i].fptr == fptr)
  240.             break;
  241.     if (i >= MAXPIPES) {
  242.         fprintf(stderr,"popen: DISASTER...couldn't find file pointer in pclose\n");
  243.         exit(1);
  244.         }
  245.  
  246.     /* close the file */
  247.     fclose(fptr);
  248.  
  249.     /* now wait for the exit status */
  250.     WaitPort(poarray[i].childmsg.POm.mn_ReplyPort);
  251.     poarray[i].fptr = NULL;
  252.  
  253.     /* clean things up */
  254.     DeletePort(poarray[i].childmsg.POm.mn_ReplyPort);
  255.     free(poarray[i].childmsg.cmd);
  256.     return(poarray[i].childmsg.rc);
  257. }
  258.  
  259. /* SAS/C autoinitialization for cleanup! */
  260. void __stdargs _STD_4000_popen(void)
  261. {
  262.     short i;
  263.  
  264.     /* Close all the open pipes! */
  265.     for(i=0; i<MAXPIPES; i++)
  266.     {
  267.         if(poarray[i].fptr)
  268.         {
  269.             pclose(poarray[i].fptr);
  270.         } /* if */
  271.     } /* for */
  272.  
  273. } /* _STD_4000_popen */
  274.  
  275. #ifdef NOTDEF
  276.  
  277. char *mktemp(char * template)
  278. {
  279.     register char *cp;
  280.     register unsigned long val;
  281.  
  282.     cp = template;
  283.     cp += strlen(cp);
  284.     for (val = (unsigned long) FindTask(0L) ; ; )
  285.         if (*--cp == 'X') {
  286.             *cp = val%10 + '0';
  287.             val /= 10;
  288.         } else if (*cp != '.')
  289.             break;
  290.  
  291.     if (*++cp != 0) {
  292.         *cp = 'A';
  293.         while (access(template, 0) == 0) {
  294.             if (*cp == 'Z') {
  295.                 *template = 0;
  296.                 break;
  297.             }
  298.             ++*cp;
  299.         }
  300.     } else {
  301.         if (access(template, 0) == 0)
  302.             *template = 0;
  303.     }
  304.     return template;
  305. }
  306.  
  307. #endif
  308.  
  309. /* WATCH OUT! This only works without __saveds because of the special
  310.    SAS/C 6.1 tricks I use! Check the output with omd! */
  311. static int __interrupt childprocess(void)
  312. {
  313.     struct ExecBase *SysBase = *((struct ExecBase **)4);
  314.     struct Library *DOSBase;
  315.     struct Process  *me;
  316.     struct POmsg    *startupmsg;
  317.     int             i = RETURN_FAIL;
  318.  
  319.     /* find our process structure */
  320.     me = (struct Process *) FindTask(NULL);
  321.  
  322.     /* Wait for the parent to kick us off */
  323.     WaitPort(&me->pr_MsgPort);
  324.  
  325.     /* Get the command to execute */
  326.     startupmsg = (struct POmsg *) GetMsg(&me->pr_MsgPort);
  327.  
  328.     DOSBase = startupmsg->DOSBase;
  329.  
  330.     if(DOSBase)
  331.     {
  332.         /* Now run the command.  stdin and stdout are already set up */
  333.         i = SystemTags(startupmsg->cmd,
  334.                SYS_UserShell, 1,
  335.                TAG_DONE);
  336.     } /* if */
  337.  
  338.     if(i > 0)
  339.     {
  340.         /* UNIX compatibility ... */
  341.         i <<= 8;
  342.     } /* if */
  343.  
  344.     startupmsg->rc = i;
  345.     /* pass the exit code back to the parent */
  346.     ReplyMsg((struct Message *) startupmsg);
  347.     return(0);
  348. }
  349.